package com.bree.erp.jsf.view.pr;

import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.security.DeclareRoles;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.eclipse.birt.report.engine.api.EngineException;

import com.bree.erp.entity.ItemRequest;
import com.bree.erp.entity.Project;
import com.bree.erp.entity.PurchaseRequisition;
import com.bree.erp.entity.Status;
import com.bree.erp.jsf.httpsess.SessionDataKey;
import com.bree.erp.jsf.httpsess.UserSessionData;
import com.bree.erp.jsf.view.ItemRequestLazyView;
import com.bree.erp.report.birt.PurchaseRequestForm;
import com.bree.erp.report.birt.param.PurchaseRequestFormParam;
import com.bree.erp.report.entity.po.Item;
import com.bree.erp.report.entity.po.PurchaseRequestDataSet;
import com.bree.erp.service.ItemRequestService;
import com.bree.erp.service.ProjectService;
import com.bree.erp.service.PurchaseRequisitionService;

@DeclareRoles("MANAGER")
@ManagedBean(name="dtEditPurchaseRequisitionView")
@ViewScoped
public class EditPurchaseRequisitionView {
	
	private static Logger LOG = Logger.getLogger(EditPurchaseRequisitionView.class);
	
	private static final String PR_EDIT_PAGE = "/pr/edit";
	
	@ManagedProperty(value="#{userSession}")
	private UserSessionData userSession;
	
	@ManagedProperty(value="#{dtItemRequestLazyView}")
	private ItemRequestLazyView itemRequestLazyView;

	@EJB
	private PurchaseRequisitionService prService;
	
	@EJB
	private ItemRequestService irService;

	@EJB
	private ProjectService projectService;
	
	private PurchaseRequisition purchaseRequisition;
	
	private Long projectId;
	private String description;
	private String jobarea;
	private String remarks;
	
	private boolean dirty;
	
	@PostConstruct
	public void initPurchaseRequisition() {

		if(purchaseRequisition == null) {
			Long id = userSession.get(SessionDataKey.SELECTED_PURCHASE_REQUISITION_ID, Long.class);
			
			LOG.debug("Loading PR#" + id);
			purchaseRequisition = prService.read(id, true);
		}
		
		projectId = purchaseRequisition.getProject().getId();
		description = purchaseRequisition.getDescription();
		jobarea = purchaseRequisition.getJobarea();
		remarks = purchaseRequisition.getRemarks();
	}
	
	public PurchaseRequisition getPurchaseRequisition() {
		
		//projectId = purchaseRequisition.getProject().getId();
		//description = purchaseRequisition.getDescription();
		
		return purchaseRequisition;
	}
	
	public String save() {
		
		List<Long> forDeletion = itemRequestLazyView.getForDeletion();
		if(forDeletion != null && forDeletion.isEmpty() == false) {
			for(Long delId : forDeletion) {
				LOG.debug("deleting ItemRequest: " + delId);
				irService.delete(delId);
			}
			
			itemRequestLazyView.initForDeletion();
		}
		
		// 1st part: get key details
		PurchaseRequisition pr = purchaseRequisition;
		LOG.debug("Saving basic info: " + pr.getId() + "; " + projectId + "; " + description);
				
		// 2nd part: item requests
		List<ItemRequest> list = itemRequestLazyView.getItemRequests();
		
		
		LOG.debug("save: " + list.size());
		
		for(ItemRequest item : list) {

			if(item.getId() != null && item.getId() > 0) {
				LOG.debug("updating item request: " + item.getId());
				
				irService.update(item.getId(), item.getQuantity(), item.getRemarks());
			} else {
				LOG.debug("creating item request: #" + item.getItemNumber());
				
				Long id = userSession.get(SessionDataKey.SELECTED_PURCHASE_REQUISITION_ID, Long.class);
				
				irService.create(id, item.getPartUnit().getId(), item.getQuantity(), item.getRemarks());
			}
			
		}
		
		// 3rd part: save + audit...
		purchaseRequisition = prService.update(pr.getId(), 
				projectId, description, jobarea, remarks,
				userSession.getLoggedInUser().getId());
		
		// clear dirty
		setDirty(false);
		this.itemRequestLazyView.setDirty(false);
		
		
		return PR_EDIT_PAGE;
	}
	
	public String submitForApproval() {

		PurchaseRequisition pr = purchaseRequisition;
		purchaseRequisition = prService.submit(pr.getId());
		
		save();
		
		return PR_EDIT_PAGE;
	}
	
	public String reopen() {
		
		PurchaseRequisition pr = purchaseRequisition;
		purchaseRequisition = prService.reopen(pr.getId(), 
				userSession.getLoggedInUser().getId());
		
		return PR_EDIT_PAGE;
	}
	
	public String approve() {
		PurchaseRequisition pr = purchaseRequisition;
		purchaseRequisition = prService.approve(pr.getId(), 
				this.remarks,
				userSession.getLoggedInUser().getId());
		
		// update sequence value
		prService.updateSequence(pr.getId());
		
		return PR_EDIT_PAGE;
	}

	public List<Project> getProjects() {
		
		List<Project> list = new ArrayList<Project>();
		list.addAll(projectService.list());
		
		return list;
		
	}
	
	public boolean isStatusOpen() {
		if(purchaseRequisition != null) {
			return Status.OPEN == purchaseRequisition.getStatus();
		}
		
		return false;
	}

	public boolean isStatusPending() {
		if(purchaseRequisition != null) {
			return Status.PENDING == purchaseRequisition.getStatus();
		}
		
		return false;
	}

	public boolean isStatusApproved() {
		if(purchaseRequisition != null) {
			return Status.APPROVED == purchaseRequisition.getStatus();
		}
		
		return false;
	}
	
	public boolean isStatusArchived() {
		if(purchaseRequisition != null) {
			Status status = purchaseRequisition.getStatus();
			return Status.CLOSED == status
					|| Status.CONFIRMED == status
					|| Status.INPROGRESS == status
					|| Status.PARTIAL == status
					|| Status.RECEIVED == status
					|| Status.REJECTED == status
					|| Status.WITHDRAW == status;
		}
		
		return false;
	}
	
	public boolean isRequestEmpty() {
		
		return this.itemRequestLazyView.getItemRequests().isEmpty();
	}
    
    public void markDirty() {
    	this.setDirty(true);
    }

	public void printPdf() throws IOException, EngineException {

		FacesContext fc = FacesContext.getCurrentInstance(); 
	    ExternalContext ec = fc.getExternalContext();
	    
	    String prId = this.purchaseRequisition.getFormattedPrNumber();
	    if(StringUtils.isBlank(prId)) {
	    	prId = this.purchaseRequisition.getId() + "";
	    }

	    ec.responseReset(); // Some JSF component library or some Filter might have set some headers in the buffer beforehand. We want to get rid of them, else it may collide.
	    ec.setResponseContentType("application/pdf"); // Check http://www.iana.org/assignments/media-types for all types. Use if necessary ExternalContext#getMimeType() for auto-detection based on filename.
	    //ec.setResponseContentLength(contentLength); // Set it with the file size. This header is optional. It will work if it's omitted, but the download progress will be unknown.
	    ec.setResponseHeader("Content-Disposition", "attachment; filename=\"PR-" + prId + ".pdf\""); // The Save As popup magic is done here. You can give it any file name you want, this only won't work in MSIE, it will use current request URL as file name instead.

	    OutputStream output = ec.getResponseOutputStream();
	    
	    PurchaseRequestFormParam param = new PurchaseRequestFormParam();
	    param.setPrNumber(prId);
	    param.setProjectName(this.purchaseRequisition.getProject().getDescription());
	    param.setRequisitionDate(asString(this.purchaseRequisition.getRequisitionDate()));
	    param.setJobNumber(purchaseRequisition.getProject().getJobNumber());
	    param.setDescription(purchaseRequisition.getDescription());
	    param.setRemarks(purchaseRequisition.getRemarks());
	    param.setRequestedBy(purchaseRequisition.getCreatedBy().getDisplayName());
	    param.setApprovedBy(purchaseRequisition.getApprovedBy().getDisplayName());
	    
		PurchaseRequestForm purchaseRequestForm = new PurchaseRequestForm(param);
		PurchaseRequestDataSet purchaseRequestDataSet = new PurchaseRequestDataSet();
		purchaseRequestDataSet.setItems(transformToBirtDataSet(purchaseRequisition.getRequests()));
		purchaseRequestForm.setPurchaseRequestDataSet(purchaseRequestDataSet );

		purchaseRequestForm.render(output);
	    fc.responseComplete(); // Important! Otherwise JSF will attempt to render the response which obviously will fail since it's already written with a file and closed.

		
	}
	
	public boolean isUserPrApprover() {
		
		HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
		
		return request.isUserInRole("MANAGER");
		
	}
	
	public boolean isRemarksEditable() {
		
		if(purchaseRequisition.getStatus() == Status.OPEN) {
			return true;
		} else if(purchaseRequisition.getStatus() == Status.PENDING && this.isUserPrApprover()) {
			return true;
		}
			
		return false;
	}
	

	private String asString(Date requisitionDate) {
		
		SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy");
		
		return format.format(requisitionDate);
	}

	private List<Item> transformToBirtDataSet(Collection<ItemRequest> requests) {
		
		List<Item> items = new ArrayList<Item>();
		
		int count = 0;
		for(ItemRequest req : requests) {
			
			Item item = new Item();
			
			item.setItemNumber(++count);
			String desc = req.getPartUnit().getShortName();
			String brand = req.getPartUnit().getShortBrand();
			String partNum = req.getPartUnit().getPart();
			
			if(StringUtils.isNotBlank(brand)) {
				desc += ", " + brand.trim();
			}
			
			if(StringUtils.isNotBlank(partNum)) {
				desc += ", " + partNum; 
			}
			
			item.setDescription(desc);
			item.setUnit(req.getPartUnit().getShortUnit());
			item.setQuantity(req.getQuantity());
	
			items.add(item);
		}
		
		
		return items;
	}

	/**
	 * @return the userSession
	 */
	public UserSessionData getUserSession() {
		return userSession;
	}

	/**
	 * @param userSession the userSession to set
	 */
	public void setUserSession(UserSessionData userSession) {
		this.userSession = userSession;
	}

	/**
	 * @return the itemRequestLazyView
	 */
	public ItemRequestLazyView getItemRequestLazyView() {
		return itemRequestLazyView;
	}

	/**
	 * @param itemRequestLazyView the itemRequestLazyView to set
	 */
	public void setItemRequestLazyView(ItemRequestLazyView itemRequestLazyView) {
		this.itemRequestLazyView = itemRequestLazyView;
	}

	/**
	 * @return the projectId
	 */
	public Long getProjectId() {
		return projectId;
	}

	/**
	 * @param projectId the projectId to set
	 */
	public void setProjectId(Long projectId) {
		this.projectId = projectId;
	}

	/**
	 * @return the description
	 */
	public String getDescription() {
		return description;
	}

	/**
	 * @param description the description to set
	 */
	public void setDescription(String description) {
		this.description = description;
	}

	/**
	 * @return the dirty
	 */
	public boolean isDirty() {
		return dirty || this.itemRequestLazyView.isDirty();
	}

	/**
	 * @param dirty the dirty to set
	 */
	public void setDirty(boolean dirty) {
		this.dirty = dirty;
	}

	/**
	 * @return the jobarea
	 */
	public String getJobarea() {
		return jobarea;
	}

	/**
	 * @param jobarea the jobarea to set
	 */
	public void setJobarea(String jobarea) {
		this.jobarea = jobarea;
	}

	/**
	 * @return the remarks
	 */
	public String getRemarks() {
		return remarks;
	}

	/**
	 * @param remarks the remarks to set
	 */
	public void setRemarks(String remarks) {
		this.remarks = remarks;
	}
	
}
